#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define FILEMAXN 100
#define OPMAXN 100
#define NAMEMAXN 100
#define PATHMAXN 1000
typedef struct FileNode{
    char name[NAMEMAXN]; //文件名或者文件夹名
    char path[PATHMAXN]; //文件（夹）路径
    int flag; //区分文件或者文件夹的标识->0: 文件夹，1: 文件
    char datetime[20]; //文件创建日期
    int filenumber; //文件夹包含的文件（夹）数量
    struct FileNode** files; //文件夹包含的文件（夹）列表
    struct FileNode* pNode; //上级目录
}FileNode, *FileTree;

//日期函数，用于记录文件创建日期
//本函数可以不用看，下面的一些函数比较重要
char* getDateTime(){
    char cur_time[20];
    time_t t;
    struct tm * lt;
    time(&t);
    lt = localtime(&t); //转为时间结构
    sprintf(cur_time, "%04d/%02d/%02d %02d:%02d:%02d",lt->tm_year+1900, lt->tm_mon, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
    return cur_time;
}
//初始化文件系统，即建立一个根目录ROOT节点
FileTree init(){
    FileTree root;
    root = (FileNode *)malloc(sizeof(FileNode)); //分配空间
    strcpy(root->name, "ROOT"); //字符串拷贝函数
    strcpy(root->path, "ROOT");
    root->flag = 0; //ROOT为目录节点，标识为0
    root->filenumber = 0; //初始时所含子文件（夹）数量为0
    root->files = NULL;
    root->pNode = NULL;
    return root;
}
//md:新建文件夹
void makeDirectory(FileNode *pNode, char dirname[]){
    if(pNode->files == NULL){ //首次使用要分配空间
        pNode->files = (FileNode**)malloc(FILEMAXN * sizeof(FileNode*));
    }
    pNode->files[pNode->filenumber] = (FileNode *)malloc(sizeof(FileNode));
    FileNode *dir = pNode->files[pNode->filenumber++];
    dir->flag = 0; //目录节点，标识为0
    strcpy(dir->name, dirname);
    dir->filenumber = 0;
    dir->files = NULL;
    dir->pNode = pNode;
    //以下代码生成当前路径
    char tmp[PATHMAXN];
    strcpy(tmp, pNode->path);
    strcat(tmp, "\\");
    strcat(tmp, dirname);
    strcpy(dir->path, tmp);

}
//mf:新建文件
void makeFile(FileNode *pNode, char filename[]){
    if(pNode->files == NULL){
        pNode->files = (FileNode**)malloc(FILEMAXN * sizeof(FileNode*));
    }
    pNode->files[pNode->filenumber] = (FileNode *)malloc(sizeof(FileNode));
    FileNode *dir = pNode->files[pNode->filenumber++];
    dir->flag = 1; //文件节点，标识为1
    strcpy(dir->name, filename);
    dir->filenumber = 0;
    dir->files = NULL;
    dir->pNode = pNode;
}
//dir:列出当前目录下全部文件（夹）
void showDir(FileNode *pNode){
    int i;
    //遍历打印文件名
    for(i = 0; i < pNode->filenumber; i++){
        printf("%s ", pNode->files[i]->name);
    }
    printf("\n");
}
//cd:切换到当前路径下的某个文件夹
FileNode* enterSubDir(FileNode *pNode, char dirname[]){
    FileNode* curNode = NULL;
    int i;
    for(i = 0; i < pNode->filenumber; i++){
        if(strcmp(pNode->files[i]->name, dirname) == 0
           && pNode->files[i]->flag == 0){
            //若有此文件夹，则将当前节点切换为此文件夹
            curNode = pNode->files[i];
        }
    }
    return curNode;
}
//del:删除文件（夹）
int delFile(FileNode *pNode, char dirname[]){
   int i;
   for(i = 0; i < pNode->filenumber; i++){
        if(strcmp(pNode->files[i]->name, dirname) == 0){
            free(pNode->files[i]); //释放空间
            int j = i;
            for(; j < pNode->filenumber - 1; j++){
                pNode->files[j] = pNode->files[j + 1]; //后面节点前移
            }
            pNode->filenumber --; //子文件（夹）数量减一
        }
    }
}
void showInfo()
{
	printf("  ******************************************************\n\n");
	printf("  *                欢迎使用文件模拟系统                 *\n \n");
	printf("  ******************************************************\n\n");
	printf("  该系统目前支持如下功能：\n");
	printf("  1.切换到当前路径下的某文件夹: cd + 文件夹\n");
	printf("  2.切换到当前路径的上级文件夹: cd ..\n");
	printf("  3.在任意路径下切换回根路径ROOT: cd \\ \n");
	printf("  4.列出当前路径下的全部文件夹和文件: dir\n");
	printf("  5.在当前路径下新建文件夹: md + 文件夹名\n");
	printf("  6.在当前路径下新建文件: mf + 文件名\n");
	printf("  7.删除当前路径下的某文件(夹)名: del文件(夹)名\n");
	printf("  ******************************************************\n");
}
//主函数
int main()
{
    showInfo();
    FileTree rootDir = init(); //初始化文件系统，
    FileNode *curDir = rootDir; //切换当前节点为根节点
    char curPath[PATHMAXN] = "ROOT"; //切换当前路径为根路径
    printf("%s> ", curPath); //输出 ROOT>
    char operation[OPMAXN];
    while(gets(operation)!= EOF){ //获取输入
        char *op = strtok(operation, " ");
        char *arg = strtok(NULL, " "); //以上分割出操作命令和参数，比如cd music，则命令为cd，参数为music
        if(strcmp(op, "md") == 0){ //md
            makeDirectory(curDir, arg);
        }else if(strcmp(op, "mf") == 0){ //mf
            makeFile(curDir, arg);
        }else if(strcmp(op, "del") == 0){ //del
            delFile(curDir, arg);
        }else if(strcmp(op, "dir") == 0){ //dir
            showDir(curDir);
        }else if(strcmp(op, "cd") == 0){ //cd
            if(strcmp(arg, "..") == 0){ //cd ..
                curDir = curDir->pNode;
            }else if(strcmp(arg, "\\") == 0){ //cd \ ---切换为根目录
                curDir = rootDir;
            }else{ //cd music --进入子目录
                FileNode *pNode = curDir;
                curDir = enterSubDir(curDir, arg);
                if(!curDir){ //出现未知目录名，报错
                    printf("ERROR:\"%s\"目录下没有\"%s\", 请重新输入!\n",pNode->name, arg);
                    curDir = pNode;
                    printf("%s> ", curPath);
                    continue;
                }
            }
            strcpy(curPath, curDir->path);
        }else if(strcmp(op, "exit") == 0){ //exit 退出
            printf("已退出系统, 谢谢使用!\n", op);
            break;
        }else{ // 出现未知命令，报错
            printf("ERROR:不支持\"%s\"命令, 请重新输入!\n", op);
        }
        printf("%s> ", curPath);
    }
    return 0;
}
//测试用例如下，可直接复制执行
//当然自己构造也可以
/*
md music
md video
mf file1.txt
mf file1.txt
dir
del file1.txt
dir
cd music
mf a.mp3
mf b.mp3
dir
cd ..
cd video
mf c.mp4
mf d.mp4
dir
cd \
cd music
dir
del a.mp3
dir
exit
**/